// Workgenerator for the INT Boinc Project
// 
// This code is largely based on the reference implementation by the BOINC Team found on
//
// http://boinc.berkeley.edu/trac/wiki/WorkGeneration
//
// Author (of the remaining parts): Timo Strunk (FZK)
//
// This program is intented to be used with a php frontend, which should basically take
// care of the following tasks:
//
// a) upload supplied input files into the directoy <project_root>/userupload/<username>/<masterid>/<filename>
// b) create a workunit templae
// c) append unique <filename>s to the commandline after the <username>, the <masterid> and the <wu_template> argument
//
// submit_work username master_id workunit_template file1 file2 file3 (in the order of the workunit template)
//
// This program has to be run in the project's root directory by the user boincadm.
//

#include "config.h"
#include <cstdio>
#include <string>
#include <iostream>
using std::string;

#include "boinc_db.h"
#include "backend_lib.h"
#include "util.h"
#include "sched_util.h"
#include "error_numbers.h"

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

namespace fs = boost::filesystem;


int main(int argc, char *argv[])
{
    fs::path const upload_path_begin("/home/boincadm/projects/poem/userupload/");

    const int MAXFNLENG = 256;
    if (argc < 4)		//This is the only check - Checking should be done by the php frontend
    {
	printf("Not enough arguments\n");
		return (-1);
    }
    string username(argv[1]); //Username (first dir)
    string jobname(argv[2]); //Jobname (second dir)
    string wu_name(argv[3]); //write the name into the string first, it will be called exactly like the workunit template file (needs to be unique)

    fs::path upload_path = upload_path_begin / fs::path(username) / fs::path(jobname);
    
    if(!fs::exists(upload_path))
    {
    	std::cout << "Upload Path does not exist, was: " << upload_path.string() << std::endl;
	exit(-1);
    }

    if(!fs::exists(upload_path / fs::path(wu_name)))
    {
    	std::cout << "ERROR: Workunit Template XML not found, File was: " << (upload_path/fs::path(wu_name)).string() << std::endl;
	exit(-1);
    }
    int numfiles = argc - 4;	//(fifth argument is the first 'real' file) - numfiles is the filecount supplied on the commandline
//wu_template string -> will read the wu_template into memory
    char *wu_template;

    char *infiles[numfiles];
    for (int i = 0; i < (numfiles); ++i) {
	infiles[i] = new char[MAXFNLENG];
    }


//infiles are read directly from commandline
    for(int i = 0; i < numfiles; ++i)
    {
	strcpy(infiles[i],argv[i+4]); //take file cmd arguments and put them in the infile array
    }
    


// Taking care of the DB access
    DB_APP app;
    DB_WORKUNIT wu;
    SCHED_CONFIG config;
    if (config.parse_file("/home/boincadm/projects/poem/") == ERR_FOPEN)
    {
        std::cout << "Config File not found, please specify directory" << std::endl;
    }
    boinc_db.open(config.db_name, config.db_host, config.db_user,config.db_passwd);
    app.lookup("where name='poempp'");
    // write input files in the download directory
    //
    // dir_hier_path takes the logical filename (first argument - only the filename, not the file folder),
    // some config specific things (shouldn't be changed) and stores the resulting path in the third argument. 
    // The directory is also created, if 'true' is supplied as the final argument, so the remaining work 
    // is to copy the files into the path. Remember, that the path already contains the filename.
    //  
    for (int i = 0; i < numfiles; ++i) 
    {
	    char path[1024];
	    int retval = 0;
	retval = dir_hier_path(infiles[i], config.download_dir,
			  config.uldl_dir_fanout, path, true);
	if (retval) {
	    printf
		("Creation of the directory for file number %d has failed. Exiting now",
		 i);
	    exit(-1);
	    }
	string commandline;
	commandline += "mv userupload/";
	commandline.append(argv[1]);
	commandline += "/";
	commandline.append(argv[2]);
	commandline += "/";
	commandline += infiles[i];
	commandline += " ";
	commandline.append(path);
	int err_code = 0;
	err_code = system(commandline.c_str());
//untested
	commandline.clear();
	commandline = "chmod ug+rw ";
	commandline.append(path);
	err_code = system(commandline.c_str());
//
    }
//workunit template is the third argument, the directory is written in the following string:
    string wu_xml;
    wu_xml = "userupload/";
    wu_xml.append(argv[1]);
    wu_xml += "/";
    wu_xml.append(argv[2]);
    wu_xml += "/";
    wu_xml.append(argv[3]);

    read_file_malloc(wu_xml.c_str(), wu_template);
    wu.clear();     // zeroes all fields
    strcpy(wu.name, wu_name.c_str());
    wu.appid = app.id;
//the following config options won't get used, they are just there as a failsafe. wu_xml always overrides them
    wu.min_quorum = 2;
    wu.target_nresults = 2;
    wu.max_error_results = 5;
    wu.max_total_results = 5;
    wu.max_success_results = 5;
    wu.rsc_fpops_est = 1e10;
    wu.rsc_fpops_bound = 1e11;
    wu.rsc_memory_bound = 1e8;
    wu.rsc_disk_bound = 1e8;
    wu.delay_bound = 7 * 86400;
    int create_work_val = 0;
    create_work_val =  create_work(wu, wu_template, "templates/poempp_result.xml", "templates/poempp_result.xml", (const char **) infiles, numfiles,	//count of the supplied infiles
		config);
    if (create_work_val != 0)
    {
        std::cout << "Bad create_work returnvalue, exiting" << std::endl;
	exit(0);
    }
    for (int i = 0; i < (numfiles); ++i) {
	delete[]infiles[i];
    }
    boinc_db.close();
    printf("%d\n", wu.id);

	//the XML file  generated will be removed here:
	string commandline;
	commandline = "rm ";
	commandline.append(wu_xml);
    unsigned int err_code = system(commandline.c_str());

    return wu.id;
}

